package com.info33.platform.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.info33.platform.common.constant.TableConstant;
import com.info33.platform.common.exception.ResultException;
import com.info33.platform.common.mvc.vo.Result;
import com.info33.platform.common.util.SysUtil;
import com.info33.platform.system.dao.SysDictionaryDao;
import com.info33.platform.system.dto.SysDictionaryDTO;
import com.info33.platform.system.entity.SysDictionary;
import com.info33.platform.system.entity.SysTenant;
import com.info33.platform.system.service.SysDictionaryService;
import com.info33.platform.system.service.SysTenantService;
import com.info33.platform.system.vo.SysDictionaryVO;
import com.info33.platform.system.vo.SysUserVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author admin
 */
@Service
public class SysDictionaryServiceImpl extends ServiceImpl<SysDictionaryDao, SysDictionary> implements SysDictionaryService {

    @Autowired
    private SysDictionaryDao sysDictionaryDao;
    @Autowired
    private SysTenantService sysTenantService;

    /**
     * 根据上级 id，和数据源，返回树型结构数据
     *
     * @param id   上级 id
     * @param list 数据源
     * @return 树型结构数据
     */
    private List<SysDictionaryVO> treeStructureByIndex(Long id, List<SysDictionaryVO> list) {
        List<SysDictionaryVO> collect = list.stream().filter(l -> l.getPid().equals(id)).collect(Collectors.toList());
        collect.forEach(l -> l.setSonList(treeStructureByIndex(l.getId(), list)));
        return ObjectUtils.isEmpty(collect) ? null : collect;
    }

    /**
     * 处理租户
     *
     * @param dto         入参
     * @param currentUser 当前用户
     */
    public void disposeTenant(SysDictionaryDTO dto, SysUserVO currentUser) {
        dto.setTenantId(Optional
                .ofNullable(currentUser)
                .map(SysUserVO::getTenant)
                .map(SysTenant::getId)
                .orElse(null));
        if (!ObjectUtils.isEmpty(dto.getTenantId())) {
            return;
        }
        if (StringUtils.isEmpty(Optional.of(dto)
                .map(SysDictionaryDTO::getTenantUrl)
                .orElse(null))) {
            throw new ResultException("非法查询");
        }
        dto.setTenantId(sysTenantService.getOne(new LambdaQueryWrapper<SysTenant>()
                .eq(SysTenant::getUrl, sysTenantService.devUrl(dto.getTenantUrl()))
                .last(TableConstant.LIMIT_ONE)).getId());
    }

    @Override
    public Result<IPage<SysDictionaryVO>> appIndexesPage(Page<SysDictionary> page, SysDictionaryDTO dto, SysUserVO currentUser) {
        disposeTenant(dto, currentUser);
        return Result.ok(sysDictionaryDao.appIndexes(page, dto));
    }

    @Override
    public List<SysDictionaryVO> appIndexes(SysDictionaryDTO dto, SysUserVO currentUser) {
        disposeTenant(dto, currentUser);
        return sysDictionaryDao.appIndexes(dto);
    }

    @Override
    public IPage<SysDictionaryVO> appPid(Page<SysDictionary> page, SysDictionaryDTO dto, SysUserVO currentUser) {
        disposeTenant(dto, currentUser);
        IPage<SysDictionaryVO> vo = sysDictionaryDao.appPid(page, dto);
        // 前端菜，不会处理
        return ObjectUtils.isEmpty(vo) ? null : vo;
    }

    @Override
    public List<SysDictionaryVO> appPid(SysDictionaryDTO dto, SysUserVO currentUser) {
        disposeTenant(dto, currentUser);
        List<SysDictionaryVO> vo = sysDictionaryDao.appPid(dto);
        // 前端菜，不会处理
        return ObjectUtils.isEmpty(vo) ? null : vo;
    }

    @Override
    public Map<String, List<SysDictionaryVO>> publicIndexesList(SysDictionaryDTO dto, SysUserVO currentUser) {
        disposeTenant(dto, currentUser);
        return sysDictionaryDao.appIndexesJsonObject(dto.getIndexesList(), dto.getTenantId())
                .stream()
                .collect(Collectors.groupingBy(SysDictionaryVO::getIndexes));
    }

    @Override
    public Map<String, List<SysDictionaryVO>> publicGetIndexesList(SysDictionaryDTO dto) {
        return sysDictionaryDao.publicGetIndexesList(dto.getIndexesList())
                .stream()
                .collect(Collectors.groupingBy(SysDictionaryVO::getIndexes));
    }

    @Override
    public IPage<SysDictionaryVO> pcBack(Page<SysDictionary> page, SysDictionaryDTO dto) {
        if (ObjectUtils.isEmpty(dto.getTenantId())) {
            dto.setTenantId(sysTenantService.getOne(new LambdaQueryWrapper<SysTenant>()
                    .eq(SysTenant::getUrl, dto.getTenantUrl())
                    .last(TableConstant.LIMIT_ONE)).getId());
        }
        return sysDictionaryDao.pcBack(page, dto);
    }

    @Override
    public Result<Object> pcMove(Long id, SysUserVO sysCurrentUser) {
        SysDictionary son = this.getOne(new LambdaQueryWrapper<SysDictionary>()
                .eq(SysDictionary::getPid, id)
                .eq(SysDictionary::getDeleted, 0)
                .and(l -> l.eq(SysDictionary::getTenantId, sysCurrentUser.getTenant().getId())
                        .or()
                        .eq(SysDictionary::getCommon, 1))
                .last(TableConstant.LIMIT_ONE));
        if (!ObjectUtils.isEmpty(son)) {
            return Result.error("此字典存在子字典，请先删除子字典");
        }
        SysDictionary old = this.getById(id);
        if (!ObjectUtils.isEmpty(old.getCommon())
                && old.getCommon().equals(Boolean.TRUE)
                && Boolean.FALSE.equals(SysUtil.isSysTenantAdmin(sysCurrentUser))) {
            return Result.error("非租户管理员不可删除公共字典");
        }
        SysDictionary entity = new SysDictionary();
        entity.setId(id);
        entity.setDeleted(Boolean.TRUE);
        return Boolean.TRUE.equals(this.updateById(entity)) ? Result.ok() : Result.error(Result.RESULT_ERROR_PUBLIC_MSG);
    }

    @Override
    public Result<Object> pcEdit(SysDictionaryDTO dto, SysUserVO sysCurrentUser) {
        SysDictionary entity = new SysDictionary();
        BeanUtils.copyProperties(dto, entity);
        SysDictionary old = this.getById(dto.getId());
        // 检查公共字典权限
        if (Boolean.FALSE.equals(SysUtil.isSysTenantAdmin(sysCurrentUser))
                && !ObjectUtils.isEmpty(old.getCommon())
                && old.getCommon().equals(Boolean.TRUE)) {
            return Result.error("非租户管理员不可编辑公共字典");
        }
        // 检查索引
        boolean b = !StringUtils.hasText(entity.getIndexes())
                || !entity.getIndexes().equals(old.getIndexes());
        if (StringUtils.hasText(entity.getIndexes())
                && b
                && !ObjectUtils.isEmpty(this.getOne(new LambdaQueryWrapper<SysDictionary>()
                .eq(SysDictionary::getIndexes, entity.getIndexes())
                .ne(SysDictionary::getId, old.getId())
                .and(l -> l.eq(SysDictionary::getCommon, Boolean.TRUE)
                        .or()
                        .eq(SysDictionary::getTenantId, sysCurrentUser.getTenant().getId()))
                .last(TableConstant.LIMIT_ONE)))) {
            return Result.error("索引 " + entity.getIndexes() + " 已经存在");
        }
        return Boolean.TRUE.equals(this.updateById(entity)) ? Result.ok() : Result.error(Result.RESULT_ERROR_PUBLIC_MSG);
    }

    @Override
    public Result<Object> pcAdd(SysDictionary entity, SysUserVO sysCurrentUser) {
        entity.setPid(ObjectUtils.isEmpty(entity.getPid()) ? 1L : entity.getPid());
        // 公共字典
        if (Boolean.TRUE.equals(SysUtil.isSysTenantAdmin(sysCurrentUser))) {
            entity.setCommon(Boolean.TRUE);
        } else {
            entity.setCommon(Boolean.FALSE);
        }
        // 检查索引
        if (!StringUtils.isEmpty(entity.getIndexes())) {
            SysDictionary indexOld = this.getOne(new LambdaQueryWrapper<SysDictionary>()
                    .eq(SysDictionary::getIndexes, entity.getIndexes())
                    .and(l -> l.eq(SysDictionary::getCommon, Boolean.TRUE)
                            .or()
                            .eq(SysDictionary::getTenantId, sysCurrentUser.getTenant().getId()))
                    .last(TableConstant.LIMIT_ONE));
            if (!ObjectUtils.isEmpty(indexOld)) {
                return Result.error("索引 " + entity.getIndexes() + " 已经存在");
            }
        }
        // 赋值序列码
        SysDictionary one = this.getOne(new QueryWrapper<SysDictionary>()
                .eq(TableConstant.PID, entity.getPid())
                .orderByDesc("code")
                .last(TableConstant.LIMIT_ONE));
        if (ObjectUtils.isEmpty(one)) {
            SysDictionary parent = this.getById(entity.getPid());
            entity.setCode(parent.getCode() + "1000");
        } else {
            int i = Integer.parseInt(one.getCode().substring(one.getCode().length() - 4), 16);
            if (i > Integer.parseInt("fff9", 16)) {
                return Result.error("该项下字典已达到上限，不可继续新增");
            }
            i++;
            entity.setCode(one.getCode().substring(0, one.getCode().length() - 4) + Integer.toString(i, 16));
        }
        return Boolean.TRUE.equals(this.save(entity)) ? Result.ok() : Result.error(Result.RESULT_ERROR_PUBLIC_MSG);
    }

    @Override
    public List<SysDictionaryVO> pcTree(Long pid) {
        return sysDictionaryDao.pcTree(pid);
    }

    @Override
    public List<SysDictionaryVO> pcTreeListByCode(String indexes, SysUserVO currentUser) {
        return sysDictionaryDao.getTreeStructureSource(indexes, null, currentUser.getTenant().getId())
                .stream()
                // 去除索引自身
                .filter(l -> !indexes.equals(l.getIndexes()))
                .collect(Collectors.toList());
    }

    @Override
    public List<SysDictionaryVO> treeStructure(SysDictionaryDTO dto, SysUserVO currentUser) {
        disposeTenant(dto, currentUser);
        List<SysDictionaryVO> list = sysDictionaryDao.getTreeStructureSource(dto.getIndexes(), dto.getPid(), dto.getTenantId());
        if (ObjectUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        Long pid;
        if (StringUtils.hasText(dto.getIndexes())) {
            // 根据索引查询
            pid = list.stream().filter(l -> dto.getIndexes().equals(l.getIndexes())).limit(1).collect(Collectors.toList()).get(0).getId();
        } else {
            // 根据 pid 查询
            pid = list.stream().filter(l -> l.getId().equals(dto.getPid())).limit(1).collect(Collectors.toList()).get(0).getId();
        }
        return treeStructureByIndex(pid, list);
    }

    @Override
    public List<SysDictionaryVO> publicBrother(SysDictionaryDTO dto, SysUserVO currentUser) {
        disposeTenant(dto, currentUser);
        List<SysDictionaryVO> list = sysDictionaryDao.listBrotherByDto(dto);
        if (!ObjectUtils.isEmpty(dto.getId())) {
            return list;
        }
        // 多个 id 做特殊处理
        List<SysDictionaryVO> vo = new ArrayList<>();
        Map<Long, List<SysDictionaryVO>> map = list.stream().collect(Collectors.groupingBy(SysDictionaryVO::getPid));
        for (Long id : dto.getIds()) {
            map.forEach((k, v) -> {
                if (v.stream().anyMatch(l -> l.getId().equals(id))) {
                    SysDictionaryVO dictionaryVO = new SysDictionaryVO();
                    dictionaryVO.setSonList(v);
                    vo.add(dictionaryVO);
                }
            });
        }
        return vo;
    }

}